package com.token.sysflow.core;

import com.token.base.Pl;
import com.token.sql.IntegrateSql;
import com.token.sysflow.bean.FSysApproveProcessT;
import com.token.sysflow.enumerate.ApprovalTypeEnum;
import com.token.sysflow.enumerate.FlowStatusEnum;
import com.token.sysflow.enumerate.FlowTypeEnum;
import com.token.sysflow.enumerate.StepTypeEnum;
import com.token.sysflow.exception.ErrorCodeEnum;
import com.token.sysflow.exception.FlowException;
import com.token.sysflow.hander.*;
import com.token.sysflow.impl.AbstractFlowHandlerImpl;
import com.token.sysflow.impl.SubmitFlowImpl;

import java.util.Objects;

/**
 * 提交
 *
 * @author chenjianxiong 2020/4/13
 */
public class SubmitFlow extends AbstractFlowCore {
    protected SubmitFlowImpl submitFlow;
    private String flowNo;

    /**
     * 每次提交
     * @param iSql 类库
     * @param process 审批对象
     * @throws Exception 抛出错误
     */
    public SubmitFlow(IntegrateSql iSql, ApproveProcess process) throws Exception {
        super(iSql, process);
    }

    /**
     * 退回时使用
     * @param iSql 类库
     * @param keyUnid 关联Id
     * @throws Exception 抛出错误
     */
    public SubmitFlow(IntegrateSql iSql, String keyUnid) throws Exception {
        super(iSql, keyUnid);
    }

    /**
     * 第一次提交
     * @param iSql 类库
     */
    public SubmitFlow(IntegrateSql iSql) throws Exception{
        super(iSql);
    }


    /**
     * 创建流程单据号
     * @throws Exception 抛出错误
     */
    private void createFlowNo() throws Exception{
        synchronized(SubmitFlow.class) {
            FlowNo flowno = new FlowNo(super.getISql(),super.getFromFlow(),submitFlow.getAppKeyId());
            flowNo = flowno.getNo();
            flowno.close();
            System.out.println("创建单据号：" + flowNo);
        }
    }


    /**
     * 提交前的处理: 判断流程状态，判断当前办理人，更新当前办理人结束
     * @throws Exception 抛出错误
     */
    protected void submitFlowHandlerBefore() throws Exception{
        //检查流程状态，结束和终止不允许操作
        checkFlowStatus();

        //判断当前用户是否是当前办理人
//        System.out.println("submitFlow.getActionUser() = " + submitFlow.getActionUser());
        if (!approveProcess.isStepApproves(submitFlow.getActionUser(),ApproveProcess.STATUS_IND)) {
            throw new FlowException(ErrorCodeEnum.CHECK_APPROVE,submitFlow.getActionUser());
        }

        //更新当前办理状态结束
        approveProcess.updateApproverToEnd(this.getFromStep(), submitFlow.getActionUser(), submitFlow.getOpinions(), submitFlow.getHSResult());

        //写入环节记录
        handleFlowRecord(submitFlow.getActionUser());
    }

    /**
     * 提交后的处理：流程事件，对外接口
     */
    protected void submitFlowHandlerAfter(){

        //处理流程事件
        super.handleFlowEvent();

        //处理对外接口
        super.handleExternalApi();
    }

    /**
     * 创建流程审批数据
     * @throws Exception 抛出错误
     */
    private void createApproveProcess() throws Exception {
        ApproveProcess process = new ApproveProcess(this.getISql());
        process.setInsert();
        process.setKeyUnid(Pl.getUuid()); //单据关联ID
        process.setSysId(submitFlow.getSysId()); //租户ID
        process.setSysAddTime(submitFlow.getActionTimer()); //创建时间
        process.setSysAddUser(submitFlow.getActionUser()); //创建人
        process.setSysEditTime(submitFlow.getActionTimer()); //修改时间
        process.setSysEditUser(submitFlow.getActionUser()); //修改人
        process.setAppKeyId(submitFlow.getAppKeyId()); //关联应用编号
        process.setCreater(submitFlow.getCreater()); //创建人
        process.setApplyer(submitFlow.getApplyer()); //申请人
        process.setFlowId(submitFlow.getFlowId()); //当前流程ID
        process.setStepId(super.getFromStep().getStepId()); //当前环节ID
        process.setFlowStatus(FlowStatusEnum.START.getId()); //当前流程状态
        process.setFlowType(FlowTypeEnum.MAIN_FLOW.getId());
        //process.setSubject(""); //应用标题
        process.setFlowNo(this.flowNo); //流程单号
        process.setApprovalType(ApprovalTypeEnum.SP.getId()); //审批类型（普通审批，会审，会签，主-子流程，组织会审，组织会签）
        process.executeUpdate();
        process.setKeyId(process.getKeyUnid()); //用于后面代码的Update

        approveProcess = process;
        super.initPublic(process.getKeyUnid());

        FSysApproveProcessT processT = new FSysApproveProcessT(this.getISql());
        processT.setInsert();
        processT.setKeyUnid(process.getKeyUnid()); //单据关联ID
        processT.setAppKeyTitle(appInfo.getAppDesc()); //关联应用编号
        processT.setCreaterTitle(createPerson.getPersonName()); //创建人
        processT.setApplyerTitle(applyerPerson.getPersonName()); //申请人
        processT.setApprovalTypeTitle(ApprovalTypeEnum.SP.getName()); //审批类型（普通审批，会审，会签，主-子流程，组织会审，组织会签）
        processT.executeUpdate();
        processT.close();

        submitFlow.setKeyUnid(process.getKeyUnid()); //回写，用于写提交日志。
    }



    @Override
    public void execute(AbstractFlowHandlerImpl flowHandler) throws Exception {
        submitFlow = (SubmitFlowImpl) flowHandler;

        //检查下一环节的办理人是否传入。
        String[] arr = submitFlow.getSelectApprover();
        if (arr == null || arr.length == 0) {
            throw new FlowException(ErrorCodeEnum.APPROVER_NOFIND_ERROR);
        }

        //首次提交时，需要创建审批数据。
        if (submitFlow.isFirstSubmit()) {

            //初始化起草人、申请人、当前人。
            initUserInfo(submitFlow.getCreater(),submitFlow.getApplyer(),submitFlow.getActionUser());

            //检查应用
            super.setAppInfoByAppKeyId(submitFlow.getAppKeyId());

            //开始流程
            super.setFromFlowById(submitFlow.getFlowId());

            //开始环节
            super.setFromStep(getFromFlow().getStartStep());

            //创建单据号
            createFlowNo();
            super.getISql().commit(); //提交事务
            //-----

            //创建审批数据
            createApproveProcess();

            //写入环节记录
            handleFlowRecord(submitFlow.getActionUser());

            //设置目标流程
            super.setToFlowById(submitFlow.getFlowId());
        } else {

            //初始化起草人、申请人、当前人。
            initUserInfo(approveProcess.getCreater(),approveProcess.getApplyer(),submitFlow.getActionUser());

            //提交前的处理
            submitFlowHandlerBefore();

            //设置目标流程
            super.setToFlowById(approveProcess.getFlowId());
        }

        //设置目标环节
        super.setToStepById(submitFlow.getStepId());

        //生成新的流转记录和办理意见[当前]
        super.createFlowApproveLog(flowHandler); //必须在submitByToStepType的前面，否则子流程提交后办理意见重复。

        //根据环节类型提交
        this.submitByToStepType(submitFlow.getActionUser());


        //生成知会记录
        super.handleNotification(submitFlow.getActionUser(),submitFlow.getSelectApprover(),submitFlow.getFieldValues());
    }

    /**
     * 提交时调用
     * @param actionUserId 当前审批人
     * @throws Exception 抛出错误
     */
    public void submitByToStepType(String actionUserId) throws Exception{
        //把退回标识去掉。
        approveProcess.setReturnAction(false);
        System.out.println("main = submitByToStepType");
        //根据目标环节类型来处理。
        StepTypeEnum type = StepTypeEnum.getStepTypeByValue(super.getToStep().getStepType());
        switch (Objects.requireNonNull(type)){
            case STEPTYPE_TASK:
                submitToTask();
                break;
            case STEPTYPE_TASK_ZLC:
                submitToSub();
                break;
            case STEPTYPE_END:
                submitToEnd();
                break;
            case STEPTYPE_TASK_HQ:
                submitToHQ();
                break;
            case STEPTYPE_TASK_HS:
                submitToHS();
                break;
            default:
                throw new FlowException(ErrorCodeEnum.STEPTYPE_ERROR);
        }

    }

    /**
     * 退回调用
     * @throws Exception 抛出错误
     */
    public void returnByToStepType() throws Exception{
        StepTypeEnum type = StepTypeEnum.getStepTypeByValue(getToStep().getStepType());
        switch (Objects.requireNonNull(type)){
            case STEPTYPE_START:
            case STEPTYPE_TASK:
                submitToTask();
                break;
            case STEPTYPE_TASK_ZLC:
                submitToSub();
                break;
            case STEPTYPE_TASK_HQ:
                submitToHQ();
                break;
            case STEPTYPE_TASK_HS:
                submitToHS();
                break;
            default:
                throw new FlowException(ErrorCodeEnum.STEPTYPE_ERROR);
        }
    }

    /**
     * 处理流程环节记录。
     * @param approver 当前办理人Id
     * @throws Exception 抛出错误
     */
    protected void handleFlowRecord(String approver) throws Exception{
        flowRecord.appendFlowRecord(fromStep,approver,approveProcess.getFlowType(),submitFlow.getActionTimer());
    }

    /**
     * 提交到会签
     * @throws Exception 抛出错误
     */
    protected void submitToHQ()throws Exception{

        //更新审批数据
        super.updateApproveProcess(submitFlow);

        //写入新的办理人
        approveProcess.addToStepApprover(submitFlow.getSelectApprover());

        //提交后的处理
        submitFlowHandlerAfter();

        //添加输出参数
        approveProcess.appendFlowProcessInfo(toFlow,toStep);
    }

    /**
     * 提交到会审
     * @throws Exception 抛出错误
     */
    protected void submitToHS()throws Exception{

        //更新审批数据
        super.updateApproveProcess(submitFlow);

        //写入新的办理人
        approveProcess.addToStepApprover(submitFlow.getSelectApprover());

        //提交后的处理
        submitFlowHandlerAfter();

        //添加输出参数
        approveProcess.appendFlowProcessInfo(toFlow,toStep);
    }

    /**
     * 提交到子流程
     * @throws Exception 抛出错误
     */
    private void submitToSub()throws Exception{

        //更新审批数据
        super.updateApproveProcess(submitFlow);

        //是否初始化子流程，如果有，则删除。
        SubFlow subFlow = new SubFlow(this.getISql(),toStep.getStepId());
        if(subFlow.getSubflowReSave()){
            approveProcess.initAllFlowSub(toStep);
        }

        //创建子流程
        subFlow.createFlowSubApproveProcess(toStep,submitFlow,approveProcess);

        //提交后的处理
        submitFlowHandlerAfter();
    }

    /**
     * 提交到普通环节
     * @throws Exception 抛出错误
     */
    protected void submitToTask() throws Exception {
        //更新审批数据
        super.updateApproveProcess(submitFlow);

        //把上一环节的多余的办理人设置为停止。
        approveProcess.updateApproverIngToStop(fromStep.getStepId());

        //写入新的办理人
        approveProcess.addToStepApprover(submitFlow.getSelectApprover());

        //提交后的处理
        submitFlowHandlerAfter();

        //添加输出参数
        approveProcess.appendFlowProcessInfo(toFlow,toStep);
    }

    /**
     * 提交到结束
     * @throws Exception 抛出错误
     */
    protected void submitToEnd() throws Exception {
        //更新审批数据
        super.updateApproveProcess(submitFlow,FlowStatusEnum.END);

        //把上一环节的多余的办理人设置为停止。
        approveProcess.updateApproverIngToStop(fromStep.getStepId());

        //提交后的处理
        submitFlowHandlerAfter();

        //迁移数据到审批完成
        approveProcess.insertToEnd();
    }

    /**
     * 计算出目标环节的默认办理人
     * @throws Exception 抛出
     */
    protected void executeDefaultApprover() throws Exception{
        StepApprover stepApprover = new StepApprover(this.getISql(), this.toStep);
        stepApprover.setProcess(approveProcess);
        stepApprover.setFlowHandlerImpl(submitFlow);
        stepApprover.execute();
        submitFlow.setSelectApprover(stepApprover.getUserIdArray());
        stepApprover.close();
    }
}
